﻿using Application.Common.Interfaces;
using Application.Features.Menus.DTOs;
using AutoMapper;
using Common.Attributes;
using Common.Enums;
using Common.Interfaces;
using Domain.Entities.Identity;
using Domain.Repositories;
using MediatR;
using Microsoft.EntityFrameworkCore;
using System.ComponentModel;

namespace Application.Features.Menus.Queries.GetUserMenuByUserId;

/// <summary>
/// 查询用户的菜单
/// </summary>
[Description("查询用户的菜单")]
[GroupDescription("菜单管理")]
public class GetMenusByUserIdQuery : IRequest<IEnumerable<UserMenuTreeOutput>>
{

}

public class GetMenusByUserIdQueryHandler :
    IRequestHandler<GetMenusByUserIdQuery, IEnumerable<UserMenuTreeOutput>>
{
    private readonly IApplicationDbContext _context;
    private readonly ICurrentUserService _currentUserService;
    private readonly IMapper _mapper;
    private readonly IMenuRepository  _menuRepository;

    public GetMenusByUserIdQueryHandler(
        IApplicationDbContext context,
        IMapper mapper,
        ICurrentUserService currentUserService,
        IMenuRepository menuRepository)
    {
        _context = context;
        _mapper = mapper;
        _currentUserService = currentUserService;
        _menuRepository = menuRepository;
    }

    public async Task<IEnumerable<UserMenuTreeOutput>> Handle(GetMenusByUserIdQuery request, CancellationToken cancellationToken)
    {
        var user = await _context.Users.SingleOrDefaultAsync(x => x.Id == _currentUserService.CurrentUserId, cancellationToken);
        if (user == null) return new List<UserMenuTreeOutput>();

        var isSystemAccount = user.IsSystemAccount.HasValue && user.IsSystemAccount.Value;
        var userMenus =await _menuRepository.GetUserMenusByUserIdAsync(user.Id, isSystemAccount, cancellationToken);

        var menuTrees = _mapper.Map<IEnumerable<UserMenuTreeOutput>>(TreeConverter.ConvertToTree(userMenus.Where(x => x.Path != null && x.Meta.Hidden == false).ToList()));

        foreach ( var menuTree in menuTrees ) 
        {
            ProcessAuthsNode(menuTree, userMenus, isSystemAccount);
        }

        return menuTrees;


        static void ProcessAuthsNode(UserMenuTreeOutput node, List<Menu> userMenus, bool isSystemAccount)
        {
            if (node.Children != null)
            {
                foreach (var childNode in node.Children)
                {
                    if (childNode is UserMenuTreeOutput menuTreeChild)
                    {
                        ProcessAuthsNode(menuTreeChild, userMenus, isSystemAccount);
                    }
                    else
                    {
                        if (childNode.Meta!.Type != MetaType.Menu) continue;

                        childNode.Meta.Auths = userMenus.Where(x => x.ParentId == childNode.Id)?.Select(s => s.Code)?.ToList() ?? new List<string?>();
                    }
                }
            }
        }
    }

    /// <summary>
    /// 树结构转换
    /// </summary>
    private static class TreeConverter
    {
        public static List<Menu> ConvertToTree(List<Menu> flatList)
        {
            var rootNodes = flatList.Where(node => !node.ParentId.HasValue).ToList();

            foreach (var rootNode in rootNodes)
            {
                PopulateChildren(rootNode, flatList);
            }

            return rootNodes;
        }

        private static void PopulateChildren(Menu parentNode, List<Menu> flatList)
        {
            var children = flatList.Where(node => node.ParentId == parentNode.Id).ToList();

            foreach (var childNode in children)
            {
                PopulateChildren(childNode, flatList);
            }
            if (children.Any())
            {
                if (parentNode.Children == null)
                    parentNode.Children = new List<Menu>();

                parentNode.Children.AddRange(children);
            }
        }
    }
}